use crate::data::data_file::DataFile;
use crate::data::log_record::{LogRecodePos, LogRecord, LogRecordType};
use crate::errors::{Errors, Result};
use crate::options::Options;
use bytes::Bytes;
use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
use crate::index;

// bit_cask 存储引擎实例结构体
pub struct Engine {
    pub options: Arc<Options>,
    // act
    pub active_file: Arc<RwLock<DataFile>>,
    pub old_files: Arc<RwLock<HashMap<u32, DataFile>>>,
    pub index: Box<dyn index::Indexer>, // 数据内存索引
}
impl Engine {
    // 存储 key/value数据，key 不能为空
    pub fn put(&self, key: Bytes, value: Bytes) -> Result<()> {
        if key.is_empty() {
            return Err(Errors::KeyIsEmpty);
        }
        let mut record = LogRecord {
            key: key.to_vec(),
            value: value.to_vec(),
            rec_type: LogRecordType::NORMAL,
        };

        // 追加到活跃数据文件中
        let log_record_pos = self.append_log_record(&mut record)?;
        // 更新内存索引
        let ok = self.index.put(key.to_vec(), log_record_pos);
        if !ok {
            return Err(Errors::IndexUpdateFailed);
        }
        Ok(())
    }
    // 根据key获取对应的数据
    pub fn get(&self, key: Bytes) -> Result<Bytes> {
        // 判断key 的有效性
        if key.is_empty() {
            return Err(Errors::KeyIsEmpty);
        }
        // 从内存索引中获取key 对应数据信息
        let pos = self.index.get(key.to_vec());
        if pos.is_none() {
            return Err(Errors::KeyNotFound);
        }
        // 从对应的数据文件中获取对应的 LogRecord
        let log_recode_pos = pos.unwrap();
        let active_file = self.active_file.read();
        let old_files = self.old_files.read();
        let log_record = match active_file.get_file_id() == log_recode_pos.file_id {
            true => active_file.read_log_record(log_recode_pos.offset)?,
            false => {
                let data_file = old_files.get(&log_recode_pos.file_id);
                if data_file.is_none() {
                    // 找不到对应数据文件 返回错误
                    return Err(Errors::DataFileNotFound);
                }
                data_file.unwrap().read_log_record(log_recode_pos.offset)?
            }
        };

        // 判断LogRecord  类型
        if log_record.rec_type == LogRecordType::DELETED {
            return Err(Errors::KeyNotFound);
        }

        // 返回对应的value信息
        Ok(log_record.value.into())
    }

    // 追加写数据到活跃文件中
    fn append_log_record(&self, log_record: &mut LogRecord) -> Result<LogRecodePos> {
        let dir_path = self.options.dir_path.clone();

        // 输入文件进行编码
        let enc_record = log_record.encode();
        let record_len = enc_record.len() as u64;

        // 获取到当前活跃文件
        // .write 获取 写锁  就相当于 获取到当前文件的写锁
        let mut active_file = self.active_file.write();

        // 判断当前活跃文件是否已经达到最大限制
        if active_file.get_write_off() + record_len > self.options.data_file_size {
            // 将当前活跃文件 进行持久化
            active_file.sync()?;

            let current_fid =active_file.get_file_id();
            // 旧的数据文件中存储到map
            let mut old_files = self.old_files.write();
            let old_file = DataFile::new(dir_path.clone(), current_fid)?;
            old_files.insert(current_fid, old_file);

            // 打开新的数据文件
            let new_file = DataFile::new(dir_path.clone(), current_fid + 1)?;
            *active_file = new_file;

        }
        // 追加数据 到当前活跃文件中
        let write_off = active_file.get_write_off();
        active_file.write(&enc_record)?;

        // 根据配置项决定是否持久化
        if self.options.sync_writes {
            active_file.sync()?;
        }
       let log_record_pos = LogRecodePos {
           file_id: active_file.get_file_id(),
           offset: write_off,
       };
        Ok(log_record_pos)
    }
}
